package com.zc.framework.shiro.dao;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.springframework.util.SerializationUtils;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * Created by zc on 2016/8/19.
 */
public class RedisSessionDAO extends AbstractSessionDAO {

    private static Logger logger = LogManager.getLogger(RedisSessionDAO.class);

    private RedisShiroManager redisShiroManager;

    private String keyPrefix = "shiro_redis_session:";


    private void saveSession(Session session) {
        if(session == null
                || session.getId() == null) {
            logger.error("session or session id is null");
            return;
        }

        byte[] key = getByteKey(session.getId());
        byte[] value = SerializationUtils.serialize(session);
        session.setTimeout(redisShiroManager.getExpire() * 1000);
        this.redisShiroManager.set(key, value);
    }

    private byte[] getByteKey(Serializable sessionId) {
        String preKey = this.keyPrefix + sessionId;
        return preKey.getBytes();
    }

    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = this.generateSessionId(session);
        this.assignSessionId(session, sessionId);
        this.saveSession(session);
        return sessionId;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        if(sessionId == null){
            logger.error("session id is null");
            return null;
        }

        return (Session) SerializationUtils.deserialize(redisShiroManager.get(this.getByteKey(sessionId)));
    }

    @Override
    public void update(Session session) throws UnknownSessionException {
        this.saveSession(session);
    }

    @Override
    public void delete(Session session) {
        if(session == null
                || session.getId() == null) {
            logger.error("session or session id is null");
            return;
        }

        redisShiroManager.del(this.getByteKey(session.getId()));
    }

    @Override
    public Collection<Session> getActiveSessions() {
        Set<Session> sessions = new HashSet<>();

        Set<byte[]> keys = redisShiroManager.keys(this.keyPrefix + "*");
        if(keys != null
                && keys.size() > 0){
            for(byte[] key : keys) {
                Session s = (Session)SerializationUtils.deserialize(redisShiroManager.get(key));
                sessions.add(s);
            }
        }
        return sessions;
    }

    public RedisShiroManager getRedisShiroManager() {
        return redisShiroManager;
    }

    public void setRedisShiroManager(RedisShiroManager redisShiroManager) {
        this.redisShiroManager = redisShiroManager;

        this.redisShiroManager.init();
    }

    public String getKeyPrefix() {
        return keyPrefix;
    }

    public void setKeyPrefix(String keyPrefix) {
        this.keyPrefix = keyPrefix;
    }
}
